import uctypes, os
    
# http://www.gnu.org/software/tar/manual/html_node/Standard.html
# TODO: uctypes неуниверсален, нужно рефакторить
TAR_HEADER = {
    "name": (uctypes.ARRAY | 0, uctypes.UINT8 | 100),
    "size": (uctypes.ARRAY | 124, uctypes.UINT8 | 11),
}

DIRTYPE = "dir"
REGTYPE = "file"


def roundup(val, align):
    return (val + align - 1) & ~(align - 1)


class FileSection:
    def __init__(self, f, content_len, aligned_len):
        self.f = f
        self.content_len = content_len
        self.align = aligned_len - content_len

    def read(self, sz=65536):
        if self.content_len == 0:
            return b""
        if sz > self.content_len:
            sz = self.content_len
        data = self.f.read(sz)
        sz = len(data)
        self.content_len -= sz
        return data

    def readinto(self, buf):
        if self.content_len == 0:
            return 0
        if len(buf) > self.content_len:
            buf = memoryview(buf)[: self.content_len]
        sz = self.f.readinto(buf)
        self.content_len -= sz
        return sz

    def skip(self):
        sz = self.content_len + self.align
        if sz:
            buf = bytearray(16)
            while sz:
                s = min(sz, 16)
                self.f.readinto(buf, s)
                sz -= s


class TarInfo:
    def __str__(self):
        return "TarInfo(%r, %s, %d)" % (self.name, self.type, self.size)


class TarFile:
    def __init__(self, name=None, fileobj=None):
        if fileobj:
            self.f = fileobj
        else:
            self.f = open(name, "rb")
        self.subf = None

    def next(self):
        if self.subf:
            self.subf.skip()
        buf = self.f.read(512)
        if not buf:
            return None

        h = uctypes.struct(uctypes.addressof(buf), TAR_HEADER, uctypes.LITTLE_ENDIAN)

        # Empty block means end of archive
        if h.name[0] == 0:
            return None

        d = TarInfo()
        d.name = str(h.name, "utf-8").rstrip("\0")
        d.size = int(bytes(h.size), 8)
        d.type = [REGTYPE, DIRTYPE][d.name[-1] == "/"]
        self.subf = d.subf = FileSection(self.f, d.size, roundup(d.size, 512))
        return d

    def __iter__(self):
        return self

    def __next__(self):
        try:
            v = self.next()
            if v is None:
                raise StopIteration
            return v
        except: pass

    def extractfile(self, tarinfo):
        return tarinfo.subf

def rmtree(top):
    for path, dirs, files in os.walk(top, False):
        for f in files:
            os.unlink(path + "/" + f)
        os.rmdir(path)

def copyfileobj(src, dest, length=512):
    if hasattr(src, "readinto"):
        buf = bytearray(length)
        while True:
            sz = src.readinto(buf)
            if not sz:
                break
            if sz == length:
                dest.write(buf)
            else:
                b = memoryview(buf)[:sz]
                dest.write(b)
    else:
        while True:
            buf = src.read(length)
            if not buf:
                break
            dest.write(buf)


def copyfile(src, dst, follow_symlinks=True):
    assert follow_symlinks
    with open(src, "rb") as srcf, open(dst, "wb") as dstf:
        copyfileobj(srcf, dstf)
def log(txt):
    print(txt)

print('\033[2JWelcome to GearBox, QubicOS installer solution.\n\nQubicOS will be extracted in root and automatic launched.\n( 1/3 ) Please wait analyzing distro.csv...')

f = 'distro.csv'
t = TarFile(f)
total_items = 0
for i in t:
    if i == None: break
    else: total_items += 1

print("( 2/3 ) Preparing to extraction...")
t = TarFile(f)
print("( 3/3 ) Extraction started")

for idx, i in enumerate(t):
        try:
            if i == None: break
            percent = (idx + 1) / total_items * 100
            print(f"( {round(percent)}% ) Extracting: {i.name}")
            if i.name in ["main.py", "apps/rdm.py"]: continue
            if i.type == DIRTYPE:
                os.mkdir(i.name[:-1])
            else:
                if '/' in i.name:
                    old = os.getcwd()
                    for directory in i.name.split('/')[:-1]:
                        try:
                            os.mkdir(directory)
                        except: pass
                        os.chdir(directory)
                    os.chdir(old)
                f = t.extractfile(i)
                copyfileobj(f, open(i.name, "wb"))
        except: continue
log(f'Succesfuly installed!')
execfile('/kernel/kernel.py')
